home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 4 / Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso / Pearls / midi / misc / Midi2TeX / src / tp_midi.pas < prev    next >
Pascal/Delphi Source File  |  1992-11-20  |  26KB  |  704 lines

  1. UNIT TP_MIDI;
  2.  
  3. INTERFACE
  4. uses DOS,
  5.      TP_decl,
  6.      TP_Misc,
  7.      TP_debug,
  8.      TP_heap1,
  9.      TP_M2TF2;
  10.  
  11. Procedure InsertRest(VAR ThisTrack : TrackRecord);
  12. Procedure ReadMetaEvent( VAR ThisTrack : TrackRecord);
  13. Function EndOfTrackReached(VAR ThisTrack:TrackRecord):boolean;
  14. Procedure WriteTexHeader;
  15. Function GetPortees: String;
  16. Function StaffIndex(No : Byte): String;
  17. Procedure Quantize(VAR N : NoteRecPoint);
  18. Procedure ReadDeltaTime(VAR ThisTrack : TrackRecord);
  19. Procedure ReadEvent(VAR ThisTrack : TrackRecord);
  20. Procedure ChangeContext(N : NoteRecPoint);
  21.  
  22. IMPLEMENTATION
  23. (********************************************)
  24.    Function StaffIndex(No : Byte): String;
  25. (********************************************)
  26. Begin
  27. Case No  OF
  28.    1  :  StaffIndex:='i';
  29.    2  :  StaffIndex:='ii';
  30.    3  :  StaffIndex:='iii';
  31.    4  :  StaffIndex:='iv';
  32.    5  :  StaffIndex:='v';
  33.    6  :  StaffIndex:='vi';
  34.    7  :  StaffIndex:='vii';
  35.    8  :  StaffIndex:='viii';
  36.    9  :  StaffIndex:='ix';
  37.    10 :  StaffIndex:='x';
  38. Else
  39.    ErrorExit(8);
  40. End; (* case *)
  41. End;
  42.  
  43.  
  44. (**********************************************)
  45.    Function GetPortees: String;
  46. (**********************************************)
  47. VAR TmpSTr          : String;
  48.     curinstr,
  49.     curtr,staff,
  50.     StartStaff,
  51.     nStaffsInInstr  : Byte;
  52.     StartFound      : Boolean;
  53. Begin
  54. TmpStr:='';
  55. StartFound:=FALSE;
  56. For curinstr:=1 to 1  Do (* this version only supports one instrument *)
  57.     Begin
  58.     staff:=1;
  59.     For curtr:=ntracks downto 1 do
  60.        With TrackArray[TrackOrder[curtr]] Do
  61.           Begin
  62.           If Not Skip Then
  63.              Begin
  64.              If NOT StartFound Then
  65.                  Begin
  66.                  If Instrument Then
  67.                     Begin
  68.                     StartStaff:=Staff;
  69.                     StartFound:=TRUE;
  70.                     nStaffsInInstr:=1;
  71.                     End
  72.                  End
  73.              Else
  74.                  Begin
  75.                  If Instrument Then INC(nStaffsInInstr);
  76.                  End;
  77.              Inc(Staff);
  78.              End
  79.           End; (* With *)
  80.     TmpStr:='\nbportees'+StaffIndex(StartStaff)+'='+B2S(nStaffsInInstr);
  81.     End; (* for next curinstr *)
  82. GetPortees:=TmpStr;
  83. End;
  84.  
  85. (**********************************************)
  86.    Procedure WriteTexHeader;
  87. (**********************************************)
  88. {$IFDEF ST}
  89. Var Year,Month,Day,DoW : Integer;
  90. {$ENDIF}
  91. {$IFDEF PC}
  92. Var Year,Month,Day,DoW : Word;
  93. {$ENDIF}
  94. Begin
  95.       GetDate(Year,Month,Day,DoW);
  96.       WriteLn(TexFile,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
  97.       WriteLn(TexFile,'%    TEX translation of MIDI File :');
  98.       With MidiFileName Do
  99.       WriteLn(TexFile,'%          ',n,e);
  100.       WriteLn(TexFile,'% ');
  101.       WriteLn(TexFile,'%        Written by Hans Kuykens');
  102.       WriteLn(TeXFile,'%  this translation of date : '+W2S(Day)+'-'+W2S(Month)+'-'+W2S(Year));
  103.       WriteLn(TexFile,'%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%');
  104.       WriteLn(TexFile,'\input musicnft');
  105.       WriteLn(TexFile,'\input musictex');
  106.       WriteLn(TexFile,'\input musicadd');
  107.       WriteLn(TexFile,'\input musictrp');
  108.       WriteLn(TexFile,'\normal');
  109.       If SizingChanged Then
  110.          Begin
  111.          WriteLn(TexFile,'\hsize '+I2S(ScoreWidth div 10)+'mm \vsize '+I2S(ScoreHeight div 10)+'mm');
  112.          WriteLn(TexFile,'\musicsize='+I2S(MusicSize));
  113.          WriteLn(TeXFile,'\elemskip=',I2S(Round(Elemskip/PT)),'pt%');
  114.          End;
  115.       If ninstruments>0 Then
  116.          Begin
  117.          WriteLn(TexFile,'\def\nbinstruments{'+B2S(ntracks-NoOfSkips-(nTracksInInstr-1))+'}');
  118.          WriteLn(TeXFile,GetPortees);
  119.          End
  120.       Else
  121.          WriteLn(TexFile,'\def\nbinstruments{'+B2S(ntracks-NoOfSkips)+'}');
  122.       
  123.       (*WriteLn(TexFile,'\signaturegenerale{0}'); *)
  124.       WriteLn(TexFile,'\generalsignature{'+SI2S(PieceContr.KeySign)+'}\relax');
  125.  
  126.       WriteLn(TeXFile,'%\centerline{\enorme PUT A NAME HERE and remove %}');
  127.       With TeXFileName DO
  128.       WriteLn(TeXFile,'\medskip\centerline{\moyen '+n+e+'}');
  129.       WriteLn(TeXFile,'\rightline{translation by MIDI2TeX}');
  130.       WriteLn(TeXFile,'\rightline{by H.J.P. Kuykens}');      
  131. End; (* WriteTexHeader *)
  132.  
  133. (********************************************)
  134.     Procedure FinishTeXHeader(num,den : Byte);
  135. (********************************************)
  136. VAR  i,j,k  :  Byte;
  137.  
  138. (*-----------------------------------------------*)
  139.   function FindStaff(ThisTrack : Integer):Integer;
  140. (*-----------------------------------------------*)
  141. (* Watch it ! If the track is in an instrument than the parameter string *)
  142. (* must be altered of cleftoks#                                          *)
  143. VAR i,j : Integer;
  144. Begin
  145. i:=ntracks;
  146. j:=1;
  147. While TrackOrder[i]<>ThisTrack Do
  148.   Begin
  149.   If NOT TrackArray[TrackOrder[i]].SKIP Then Inc(J);
  150.   Dec(i);
  151.   End;
  152. FindStaff:=j;
  153. End; (* FindStaff *)
  154.  
  155. (*-----------------------------------------------*)
  156.   function FindClefStaff(ThisTrack : Integer):String;
  157. (*-----------------------------------------------*)
  158. VAR i,j ,k : Integer;
  159.     C      : String[2];
  160. Begin
  161. i:=ntracks;
  162. j:=1;
  163. k:=1;
  164. Str(Ord(TrackArray[TrackOrder[ThisTrack]].Clef),C);
  165. While TrackOrder[i]<>ThisTrack Do
  166.   Begin
  167.   If NOT TrackArray[TrackOrder[i]].SKIP Then
  168.      If TrackArray[TrackOrder[i]].Instrument Then
  169.         Inc(k)
  170.      ELse
  171.         Inc(J);
  172.   Dec(i);
  173.   End;
  174. case k of
  175.    1 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{'+C+'}{0}{0}{0}}';
  176.    2 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{'+C+'}{0}{0}}';
  177.    3 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{0}{'+C+'}{0}}';
  178.    4 : FindClefStaff:='\cleftoks'+StaffIndex(j)+'{{0}{0}{0}{'+C+'}}';
  179. Else
  180.    Warning('Something wrong with cleftoks#, check it out !');
  181.    FindClefStaff:='\cleftoks??';
  182. End;
  183.  
  184. End; (* FindClefStaff *)
  185.  
  186. Begin
  187. WriteLn(TexFile,'\generalmeter{\meterfrac{',Num,'}{',Power(2,Den),'}}%');
  188. (* determine clefs *)
  189. For i:=1 to ntracks do
  190.   Begin
  191.   If TrackArray[i].Clef>VIOLIN Then
  192.      Begin
  193.      WriteLn(TeXFile,FindClefStaff(i));
  194.      End;
  195.   End;
  196. WriteLn(TexFile,'%\raggedlinestrue % uncomment for ragged right lines ');
  197. WriteLn(TeXFile,'%\relativeaccidentals');
  198. WriteLn(TexFile,'\debutmorceau');
  199. TeXHeaderFinished:=TRUE;
  200. End;
  201.  
  202. (********************************************)
  203.     Procedure ChangeContext(N : NoteRecPoint);
  204. (********************************************)
  205. Begin
  206. With N^ DO
  207.    Case Event Of
  208.       KEYSIGN   : Begin
  209.                   WriteLn(TeXFile,'\signaturegenerale{'+B2S(NoteVal)+'}\changecontext%');
  210.                   With PieceContr DO
  211.                           Begin
  212.                           KeySign:=NoteVal;
  213.                           Minor:=Velocity;
  214.                           End;
  215.                   End;
  216.       SIGNATURE : Begin
  217.                   WriteLn(TexFile,'\generalmeter{\meterfrac{',Noteval,'}{',Power(2,Velocity),'}}%');
  218.                   WriteLn(TeXFile,'\changecontext%');
  219.                   With PieceContr DO
  220.                           Begin
  221.                           Num:=NoteVal;Den:=Velocity;
  222.                           TicksPerMeasure:=4*Division*Num div Power(2,Den);
  223.                           If NOT PartOverRule Then
  224.                              PartTime:=TicksPerMeasure div Num;
  225.                           nparts:=TicksPerMeasure div PartTime;
  226.                           Twindow:=Division div 16;
  227.                           
  228.                           End;
  229.                   End;
  230.    End; (* case *)
  231. End;
  232.  
  233. (*****************************************************)
  234.     Procedure Quantize(VAR N : NoteRecPoint); (* Still needs updating !!! *)
  235. (*****************************************************)
  236. VAR dt : Longint;
  237.     T  : MeasureTime;
  238. Begin
  239. With N^ Do
  240.    Begin
  241.    dt:=TimeDiff(EndTime,StartTime);
  242.    if dt>QuantTime Then
  243.       Begin
  244.       (* quantize notelength first *)
  245.       dt:=QuantTime*Round(dt/QuantTime); 
  246.       SetTime(T,0,dt);
  247.       (* quantize start time and end time*)
  248.       StartTime.MPart:=QuantTime*Round(StartTime.MPart/QuantTime);
  249.       AddTime(StartTime,T,EndTime);
  250.       End
  251.    End;
  252. End;
  253.  
  254. (*******************************************************)
  255.     Procedure ReadDeltaTime(VAR ThisTrack : TrackRecord);
  256. (*******************************************************)
  257. VAR delta : LONGINT ;
  258. Begin
  259. With ThisTrack DO
  260.    Begin
  261.       OldOldTime:=OldTime;
  262.       OldTime:=CurTime;
  263.       delta:=ReadVarLen(FilRec);
  264.   (*    WriteDebugInfo('read deltatime :'+LI2S(delta)); *)
  265.       With CurTime DO 
  266.          IF PieceContr.TicksPerMeasure=0 Then
  267.             INC(Mpart,delta)
  268.          Else
  269.             Begin         
  270.             INC(MPart,delta);
  271.             WITH PieceContr DO
  272.               IF MPart>=TicksPerMeasure Then
  273.                   BEGIN
  274.                   Measure:=Measure+ (MPart div TicksPerMeasure);
  275.                   MPart:=MPart MOD TicksPerMeasure;
  276.                   End;
  277.             End;
  278.    End;
  279. End; 
  280.  
  281. (******************************************************)
  282.     Procedure InsertRest(VAR ThisTrack : TrackRecord);
  283. (******************************************************)
  284. VAR N        : NoteRecPoint;
  285.     TmpTime1,
  286.     TmpTime2 : MeasureTime;
  287. Begin
  288. SetTime(TmpTime1,MeasureCount,0);
  289. SetTime(TmpTime2,MeasureCount+1,0);
  290. With ThisTrack Do
  291.   Begin
  292.   N:=GetFreeNote;
  293.   N^.Event:=REST;
  294.   (*
  295.   If (TimeDiff(TmpTime2,LastNoteOffTime)>0) AND
  296.      (TimeDiff(TmpTime1,LastNoteOffTime)<=0) Then
  297.      N^.STartTime:=LastNoteOffTime
  298.   Else
  299.      N^.STartTime:=TmpTime1;
  300.   If TimeDiff(TmpTime2,CurTime)<0 Then
  301.      N^.EndTime:=TmpTime2
  302.   Else
  303.      N^.EndTime:=CurTime;
  304.   *)
  305.   N^.EndTime:=CurTime;
  306.   N^.STartTime:=LastNoteOffTime;
  307.   Append(NoteList,N);
  308.   WriteDebugInfo('Inserted Rest between '+W2S(N^.StartTime.Measure)+':'+LI2S(N^.StartTime.MPart)+
  309.                   ' and '+W2S(N^.EndTime.Measure)+':'+LI2S(N^.EndTime.MPart));
  310.   End;
  311. End;
  312.  
  313.  
  314.  
  315. (******************************************************)
  316.     Procedure ReadNoteOn(MidCode : Byte;
  317.                          VAR ThisTrack : TrackRecord);
  318. (******************************************************)
  319. VAR N,P  : NoteRecPoint;
  320.     dt : LongInt;
  321.     TmpVal,TmpVel : Byte;
  322. Begin
  323.  
  324. With ThisTrack Do
  325.     Begin
  326.     TmpVal:=ReadByte(FilRec);
  327.     TmpVel:=ReadByte(FilRec); (* if TmpVel=0 Than it is a Note OFF ! *)
  328.  
  329.     If TmpVel>0 Then
  330.         Begin
  331.  
  332.         If (NotesSounding=0) Then
  333.            Begin
  334.            dt:=TimeDiff(CurTime,LastNoteOffTime);
  335.            If Quantizing Then
  336.               Begin
  337.               If dt>QuantTime Then (* only insert rest if longer than QuantTime *)
  338.                 InsertRest(ThisTrack)
  339.               End
  340.            Else
  341.               If dt>=(PieceContr.Division div 4) Then (* only insert rest if longer than 1/16th note *)
  342.                  InsertRest(ThisTrack)
  343.            End
  344.         Else (* There are notes sounding, check if same note is already on *)
  345.            Begin
  346.            FirstNote(NoteList,N);
  347.            P:=NIL;
  348.            while N<>P do
  349.               Begin
  350.               If P=NIL then P:=N;
  351.               If (N^.NoteVal=TmpVal) AND (N^.Event=NOTEON) Then (* close this note down *)
  352.                  Begin
  353.                  N^.EndTime:=CurTime;
  354.                  N^.Event:=NOTEOFF;
  355.                  LastNoteOffTime:=CurTime;
  356.                  If NotesSounding>0 Then
  357.                     Dec(NotesSounding);
  358.                  WriteDebugInfo('Closed down a double note');
  359.                  End;
  360.               NextNote(N,N);
  361.               End
  362.            End;
  363.  
  364.            N:=GetFreeNote;
  365.            Append(NoteList,N);
  366.            With N^ Do
  367.               Begin
  368.               MidiChnl:=MidCode MOD 15;
  369.               NoteVal:=TmpVal;
  370.               Velocity:=TmpVel;
  371.               Event:=NOTEON;
  372.               StartTime:=CurTime;
  373.               SetTime(EndTime,1000,0); (* set EndTime to infinity *)
  374.               WriteDebugInfo((*W2S(NoteArPoint)+*)'NoteOn : '+B2S(NoteVal)+' Vel : '+B2S(velocity)+
  375.                                      ' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
  376.               End;
  377.            Inc(NotesSounding);
  378.            End
  379.         Else (* the Velocity value is 0 set Note Off *)
  380.            Begin
  381.            WriteDebugInfo('NoteOff : '+B2S(TmpVal)+
  382.                                  ' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
  383.            If NoteList.Size>0 Then
  384.               Begin
  385.               LastNote(NoteList,N);  (* dit gaat soms fout ... ? *)
  386.               FirstNote(NoteList,P); (* een maat kan beginnen met een NoteOff !!!! *)
  387.               While (NOT EqualsNote(N,TmpVal)) AND (N<>P) Do
  388.                  PrevNote(N,N);
  389.  
  390.               if N=NIL Then
  391.                  ErrorExit(6)
  392.               else
  393.                  if NOT EqualsNote(N,TmpVal) Then
  394.                     WriteDebugInfo('Could not find note-ON for this note-OFF')
  395.                  else
  396.                     Begin
  397.                     If N^.Event=NOTEON Then
  398.                        Begin
  399.                        N^.EndTime:=CurTime;
  400.                        N^.Event:=NOTEOFF;
  401.                        End
  402.                     Else
  403.                        WriteDebugInfo('Note was already OFF, probably a double note...');
  404.                     End;
  405.               LastNoteOffTime:=CurTime;
  406.               If NotesSounding>0 Then
  407.                  Dec(NotesSounding);
  408.               End (* If NoteList.Size > 0 *)
  409.            Else
  410.               WriteDebugInfo('There can`t be a NoteOff if there are no notes at all !');
  411.            End; (* Set Note Off *)
  412.     End; (* With ThisTrack *)
  413. End; (* ReadNoteOn *)
  414.  
  415. (******************************************************)
  416.     Procedure ReadNoteOff(MidCode : Byte;
  417.                           VAR ThisTrack : TrackRecord);
  418. (******************************************************)
  419. VAR N,P         : NoteRecPoint;
  420.     MidiChnl,
  421.     velo,
  422.     Note        : Byte;
  423. Begin
  424. With ThisTrack Do
  425.     Begin
  426.     MidiChnl:=MidCode MOD 15;   
  427.     Note:=ReadByte(FilRec);
  428.     velo:=ReadByte(FilRec);
  429.     WriteDebugInfo('NoteOff : '+B2S(Note)+
  430.                           ' at '+W2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
  431.     If NoteList.Size>0 Then
  432.        Begin
  433.        LastNote(NoteList,N);  (* dit gaat soms fout ... ? *)
  434.        FirstNote(NoteList,P); (* een maat kan beginnen met een NoteOff !!!! *)
  435.        While (NOT EqualsNote(N,Note)) AND (N<>P) Do
  436.           PrevNote(N,N);
  437.  
  438.        if N=NIL Then
  439.           ErrorExit(6)
  440.        else
  441.           if NOT EqualsNote(N,Note) Then
  442.              WriteDebugInfo('Could not find note-ON for this note-OFF')
  443.           else
  444.              Begin
  445.              If N^.Event=NOTEON Then
  446.                 Begin
  447.                 N^.EndTime:=CurTime;
  448.                 N^.Event:=NOTEOFF;
  449.                 End
  450.              Else
  451.                 WriteDebugInfo('Note was already OFF, probably a double note...');
  452.              End;
  453.        LastNoteOffTime:=CurTime;
  454.        If NotesSounding>0 Then
  455.           Dec(NotesSounding);
  456.        End (* If NoteList.Size > 0 *)
  457.     Else
  458.        WriteDebugInfo('There can`t be a NoteOff if there are no notes at all !');
  459.     End; (* with this track *)
  460. End; (* ReadNoteOff *)
  461.  
  462.  
  463. (******************************************************)
  464.     Procedure ReadMetaText(Len : Byte;
  465.                            VAR ThisTrack : TrackRecord);
  466. (******************************************************)
  467. VAR N : NoteRecPoint;
  468. Begin
  469. With ThisTrack Do
  470.     Begin
  471.     N:=GetFreeNote;
  472.     Append(NoteList,N);
  473.     With N^ Do
  474.        Begin
  475.        Event:=TXT;
  476.        If MaxAvail>SizeOf(String20Type) Then
  477.             GetMem(MetaTxt,SizeOf(String20Type))
  478.        Else
  479.             ErrorExit(9);
  480.        StartTime:=CurTime;
  481.        EndTime:=CurTime;
  482.        EndTime.Measure:=EndTime.Measure+1;
  483.        MetaTxt^:=ReadString(FilRec,Len);     
  484.        WriteDebugInfo('MetaText :' + MetaTxt^ + ' at '+I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
  485.        End;
  486.     End;
  487. End; (* ReadText *)
  488.  
  489. (******************************************************)
  490.     Procedure ReadDamper(MidiCode : byte;
  491.                          VAR ThisTrack : TrackRecord);
  492. (******************************************************)
  493. VAR N : NoteRecPoint;
  494. Begin
  495. With ThisTrack Do
  496.     Begin
  497.     N:=GetFreeNote;
  498.     Append(NoteList,N);
  499.     With N^ Do
  500.        Begin
  501.        Event:=PEDAL;
  502.        Velocity:=ReadByte(ThisTrack.FilRec);
  503.        StartTime:=CurTime;
  504.        EndTime:=CurTime;
  505.        EndTime.Measure:=EndTime.Measure+1;
  506.        WriteDebugInfo('Pedal : at '+I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
  507.        End;
  508.     End;
  509. End; (* ReadDamper *)
  510.  
  511.  
  512. (**********************************************************)
  513.     Procedure ReadMetaEvent( VAR ThisTrack : TrackRecord);
  514. (**********************************************************)
  515. VAR 
  516.      DumStr       :  String[255];   
  517.      i,
  518.      DumInt       :  Integer; 
  519.      DumByte,
  520.      MetaType     :  Byte;
  521.      MetaByteCnt  :  Word;
  522.      MetaLength   :  LongInt;
  523.      N            :  NoteRecPoint;
  524.   
  525. Begin
  526. With ThisTrack Do 
  527.     Begin
  528.     MetaType:=ReadByte(FilRec);
  529.     MetaLength:=ReadVarLen(FilRec);
  530.     WriteDebugInfo(' Read Meta event type : '+B2S(MetaType)+' of '+
  531.                             LI2S(MetaLength)+' bytes');
  532.     MetaByteCnt:=0;
  533.     case MetaType Of
  534.         0   :       Begin
  535.                     DumByte:=ReadByte(FilRec);
  536.                     DumInt:=ReadInteger(FilRec);
  537.                     End;
  538.         1..7:       Begin  (* Text events *)
  539.                     (* DumStr:=ReadString(FilRec,MetaLength); *)
  540.                     ReadMetaText(MetaLength,ThisTrack);
  541.                     End;
  542.         32  :       DumByte:=ReadByte(FilRec); (* MIDI Chnl Prefix *)
  543.         47  :       Begin EndOfTrackRead:=TRUE; End; (* End of Track *)
  544.         81  :       Begin (* set tempo *)
  545.                     With PieceContr Do
  546.                         Begin
  547.                         Tempo:=ReadByte(FilRec);Tempo:=Tempo SHL 8;
  548.                         Tempo:=Tempo+ReadByte(FilRec);Tempo:=Tempo SHL 8;
  549.                         Tempo:=Tempo+ReadByte(FilRec);
  550.                         End;
  551.                     End;
  552.         84  :       Begin (* SMPTE OffSet *)
  553.                     DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
  554.                     DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
  555.                     DumByte:=ReadByte(FilRec);
  556.                     End;
  557.         88  :       Begin (* Time Sign *)
  558.                     
  559.                     If TeXHeaderFinished then (* store the value on the note list *)
  560.                        Begin
  561.                        N:=GetFreeNote;
  562.                        Append(NoteList,N);
  563.                        With N^ Do
  564.                           Begin
  565.                           Event:=SIGNATURE;
  566.                           NoteVal:=ReadByte(FilRec); (* NUM *)
  567.                           Velocity:=ReadByte(FilRec); (* DEN *)
  568.                           DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
  569.                           StartTime:=CurTime;
  570.                           EndTime:=CurTime;
  571.                           WriteDebugInfo('Signature : ' + B2S(NoteVal)+'/'+ I2S(Power(2,Velocity)) +' at '+
  572.                                           I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
  573.                           End
  574.                        End
  575.                     Else
  576.                        With PieceContr Do
  577.                            Begin
  578.                            Num:=ReadByte(FilRec);Den:=ReadByte(FilRec);
  579.                            FinishTeXHeader(Num,Den);
  580.                            DumByte:=ReadByte(FilRec);DumByte:=ReadByte(FilRec);
  581.                            TicksPerMeasure:=4*Division*Num div Power(2,Den);
  582.                            If NOT PartOverRule Then
  583.                              PartTime:=TicksPerMeasure div Num
  584.                            Else
  585.                              PartTime:=4*Division div PartType;
  586.                            nparts:=TicksPerMeasure div PartTime;
  587.                            Twindow:=Division div 16;
  588.                            If Quantizing Then QuantTime:=Division*4 div QuantTime;
  589.                            WriteDebugInfo('4*'+I2S(Division)+'*'+B2S(Num)+' div '+
  590.                                                    B2S(Den)+' = '+W2S(TicksPerMeasure)+' Ticks per measure');
  591.                            End;
  592.                     End;
  593.         89  :       Begin  (* Key signature *)
  594.                     If TeXHeaderFinished then (* store the value on the note list *)
  595.                        Begin
  596.                        N:=GetFreeNote;
  597.                        Append(NoteList,N);
  598.                        With N^ Do
  599.                           Begin
  600.                           Event:=KEYSIGN;
  601.                           NoteVal:=ReadByte(FilRec); (* KeySign *)
  602.                           Velocity:=ReadByte(FilRec); (* Minor *)
  603.                           StartTime:=CurTime;
  604.                           EndTime:=CurTime;
  605.                           
  606.                           WriteDebugInfo('Keysign  : ' + B2S(NoteVal) + ' at '+
  607.                                          I2S(CurTime.Measure)+':'+LI2S(CurTime.MPart));
  608.                           End
  609.                        End
  610.                     Else
  611.                        With PieceContr DO
  612.                           Begin
  613.                           KeySign:=ReadByte(FilRec);
  614.                           Minor:=ReadByte(FilRec);
  615.                           If KeySign>0 Then
  616.                               WriteDebugInfo('KeySignature : '+B2S(KeySign)+' sharps ')
  617.                           Else
  618.                               WriteDebugInfo('KeySignature : '+B2S(KeySign)+' flats ');
  619.                           End; (* with *)
  620.                     End;
  621.         127 :       Begin (* specials.... *)
  622.                     For i:=1 to MetaLength Do DumByte:=ReadByte(FilRec);
  623.                     End;            
  624.     End; (* case *)                   
  625.     End;
  626. End; (* ReadMetaEvent *)
  627.  
  628.  
  629. (*****************************************************)
  630.     Procedure ReadEvent(VAR ThisTrack : TrackRecord);
  631. (*****************************************************)
  632. VAR DumByte,
  633.     MidiCode : Byte;
  634. Begin
  635. With ThisTrack Do
  636.     Begin
  637.     MidiCode:=ReadByte(FilRec);
  638.     case MidiCode Of
  639.          $90..$9F :  Begin ReadNoteOn(MidiCode,ThisTrack); StatusByte:=MidiCode; End;
  640.          $80..$8F :  Begin ReadNoteOff(MidiCode,ThisTrack); StatusByte:=MidiCode; End;
  641.          $FF      :  Begin ReadMetaEvent(ThisTrack); StatusByte:=MidiCode; End;
  642.          $A0..$AF :  Begin For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
  643.                             StatusByte:=MidiCode; End;(* polypress. *)
  644.          $B0..$BF :  Begin
  645.                      DumByte:=ReadByte(FilRec);
  646.                      case DumByte of
  647.                         $40 : ReadDamper(MidiCode,ThisTrack); { this is a damper pedal }
  648.                      Else
  649.                         DumByte:=ReadByte(FilRec);
  650.                      End; { case }
  651.                      StatusByte:=MidiCode;
  652.                      End;(* control change *)
  653.          $C0..$CF :  Begin DumByte:=ReadByte(FilRec); StatusByte:=MidiCode; End;(* progr. change *)
  654.          $D0..$DF :  Begin DumByte:=ReadByte(FilRec);
  655.                      StatusByte:=MidiCode; End;(* channel pressure *)
  656.          $E0..$EF :  Begin For i:=1 to 2 Do DumByte:=ReadByte(FilRec); StatusByte:=MidiCode; End;(* pitch wheel *)
  657.          $F8      :  Begin (* do nothing *) End; (* timing clock *)
  658.          $F0      :  Begin
  659.                      Repeat (* SysEx code *)
  660.                        DumByte:=ReadByte(FilRec);
  661.                      until DumByte=$F7;
  662.                      StatusByte:=00;
  663.                      End;
  664.          $F1      :  DumByte:=ReadByte(FilRec);(* quarter frame *)
  665.          Else        (* WriteDebugInfo(' Unknown MidiEvent, type : '+B2S(MidiCode)); *)
  666.                      (* This is a running status *)
  667.                      Begin
  668.                      RestoreLastRead(FilRec); (* This will NOT work ALWAYS !!! *)
  669.                      case StatusByte Of
  670.                           $90..$9F :  ReadNoteOn(StatusByte,ThisTrack);
  671.                           $80..$8F :  ReadNoteOff(StatusByte,ThisTrack);
  672.                           $FF      :  ReadMetaEvent(ThisTrack);
  673.                           $A0..$AF :  For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
  674.                           $B0..$BF :  For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
  675.                           $C0..$CF :  DumByte:=ReadByte(FilRec);
  676.                           $D0..$DF :  DumByte:=ReadByte(FilRec);
  677.                           $E0..$EF :  For i:=1 to 2 Do DumByte:=ReadByte(FilRec);
  678.                           $F8      :  Begin (* do nothing *) End; (* timing clock *)
  679.                           $F0      :  Repeat (* SysEx code *)
  680.                                         DumByte:=ReadByte(FilRec);
  681.                                       until DumByte=$F7;
  682.                           $F1      :  DumByte:=ReadByte(FilRec);(* quarter frame *)
  683.                      End; (* case *)
  684.                      End;
  685.     end;
  686.     End;
  687. End; (* ReadEvent *)           
  688.  
  689.  
  690. (**************************************************************)
  691.       Function EndOfTrackReached(VAR ThisTrack:TrackRecord):boolean;
  692. (*************************************************************)
  693. Begin
  694. With ThisTrack Do
  695.   If EndOfTrackRead AND
  696.      (SpillList.Size=0) AND
  697.      (NoteList.Size=0) Then
  698.      EndOfTrackReached:=TRUE
  699.   Else
  700.      EndOfTrackReached:=FALSE;
  701. End;
  702.  
  703. Begin
  704. End.